package com.demo.webapp.result;

import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.StringReader;
import java.io.Writer;
import java.util.Locale;

import javax.servlet.http.HttpServletRequest;

import org.apache.struts2.ServletActionContext;
import org.apache.struts2.views.freemarker.FreemarkerResult;
import org.apache.struts2.views.util.ResourceUtil;

import com.demo.webapp.action.TemplateProvider;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;

import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import freemarker.template.TemplateModel;

/**
 * 自定义Freemarker模板结果处理类 针对自定义模板进行渲染. 该模板由Action指定
 * 
 * @author ryuu.kk
 * 
 */
public class CustomFreemarkerResult extends FreemarkerResult {

	private static final String PARENT_TEMPLATE_WRITER = FreemarkerResult.class.getName() + ".parentWriter";

	/**
	 * 版本序列化ID
	 */
	private static final long serialVersionUID = -838955374585349497L;

	@Override
	public void doExecute(String locationArg, ActionInvocation invocation)
			throws IOException, TemplateException {
		this.location = locationArg;
		this.invocation = invocation;
		this.configuration = getConfiguration();
		this.wrapper = getObjectWrapper();

		ActionContext ctx = invocation.getInvocationContext();
		HttpServletRequest req = (HttpServletRequest) ctx.get(ServletActionContext.HTTP_REQUEST);

		if (!locationArg.startsWith("/")) {
			String base = ResourceUtil.getResourceBase(req);
			locationArg = base + "/" + locationArg;
		}

		Template template = createTemplate(locationArg, deduceLocale(), invocation.getAction());
		TemplateModel model = createModel();

		// Give subclasses a chance to hook into preprocessing
		if (preTemplateProcess(template, model)) {
			try {
				// Process the template
				Writer writer = getWriter();
				if (isWriteIfCompleted()
						|| configuration.getTemplateExceptionHandler() == TemplateExceptionHandler.RETHROW_HANDLER) {
					CharArrayWriter parentCharArrayWriter = (CharArrayWriter) req.getAttribute(PARENT_TEMPLATE_WRITER);
					boolean isTopTemplate = false;
					if (isTopTemplate = (parentCharArrayWriter == null)) {
						// this is the top template
						parentCharArrayWriter = new CharArrayWriter();
						// set it in the request because when the "action" tag
						// is used a new VS and ActionContext is created
						req.setAttribute(PARENT_TEMPLATE_WRITER, parentCharArrayWriter);
					}

					try {
						template.process(model, parentCharArrayWriter);

						if (isTopTemplate) {
							parentCharArrayWriter.flush();
							parentCharArrayWriter.writeTo(writer);
						}
					} finally {
						if (isTopTemplate && parentCharArrayWriter != null) {
							req.removeAttribute(PARENT_TEMPLATE_WRITER);
							parentCharArrayWriter.close();
						}
					}
				} else {
					template.process(model, writer);
				}
			} finally {
				// Give subclasses a chance to hook into postprocessing
				postTemplateProcess(template, model);
			}
		}
	}
	
	/**
	 * 取得Template
	 * @param name 名称
	 * @param locale Locale
	 * @param action Action
	 * @return Template
	 * @throws IOException 异常
	 */
	protected Template createTemplate(String name, Locale locale, Object action) throws IOException {
		
		Template template = null;
		if (action instanceof TemplateProvider) {
			com.demo.core.model.Template model = ((TemplateProvider)action).getTemplateModel();
			String content = model.getContent();
			template = new Template(name + ":" + model.getPath(), new StringReader(content), configuration, configuration.getDefaultEncoding());
		} else {
			template = configuration.getTemplate(name, locale);
		}
		return template;
	}
}
